import os
import shutil
import glob
import sys

def find_keil_files(base_dir, keep_uvguix=True):
    """
    查找Keil项目中的编译生成文件
    返回 (目录列表, 文件列表)
    """
    dirs_to_remove = []
    files_to_remove = []
    
    # 可能存在的输出目录（包括自定义目录）
    common_output_dirs = ["Objects", "Listings", "Build"]
    
    # 常见的编译文件模式
    file_patterns = [
        "*.axf", "*.hex", "*.map", "*.htm", "*.dep", "*.log", 
        "*.build_log.htm", "*.lst", "*.o", "*.d", "*.crf",
        "*.bak", "*.lnp", "*.iex", "*.tra", "*.cdb", "__iar*.tmp"
    ]
    
    if not keep_uvguix:
        file_patterns.append("*.uvguix.*")
    
    # 查找要删除的目录
    for dir_name in common_output_dirs:
        dir_path = os.path.join(base_dir, dir_name)
        if os.path.exists(dir_path):
            dirs_to_remove.append(dir_path)
    
    # 查找要删除的文件
    for pattern in file_patterns:
        files_to_remove.extend(glob.glob(os.path.join(base_dir, pattern), recursive=True))
    
    # 额外查找项目目录下的临时文件
    project_files = glob.glob(os.path.join(base_dir, "**", "*"), recursive=True)
    for file_path in project_files:
        if os.path.isfile(file_path):
            ext = os.path.splitext(file_path)[1].lower()
            if ext in ['.o', '.d', '.lst', '.crf']:
                files_to_remove.append(file_path)
    
    # 去重
    files_to_remove = list(set(files_to_remove))
    
    return dirs_to_remove, files_to_remove

def list_keil_files(base_dir, keep_uvguix=True):
    """
    列出Keil项目中的编译生成文件
    """
    dirs, files = find_keil_files(base_dir, keep_uvguix)
    
    print("\n" + "="*50)
    print(f"在目录中发现 {len(dirs)} 个编译目录 和 {len(files)} 个编译文件")
    print("="*50)
    
    if dirs:
        print("\n要删除的目录:")
        for d in dirs:
            print(f"  - {os.path.relpath(d, base_dir)}")
    
    if files:
        print("\n要删除的文件:")
        for f in files:
            print(f"  - {os.path.relpath(f, base_dir)}")
    
    total_size = 0
    
    # 计算目录大小
    for d in dirs:
        for root, dirs, files in os.walk(d):
            for file in files:
                fp = os.path.join(root, file)
                total_size += os.path.getsize(fp)
    
    # 计算文件大小
    for f in files:
        if os.path.exists(f):
            total_size += os.path.getsize(f)
    
    print("\n" + "="*50)
    print(f"总大小: {total_size/1024/1024:.2f} MB 将被释放")
    print("="*50 + "\n")
    
    return dirs, files

def clean_keil_project(project_path=None, keep_uvguix=True, dry_run=False, force=False):
    """
    清理Keil uVision5编译生成文件
    :param project_path: 项目路径（默认为当前目录）
    :param keep_uvguix: 是否保留uvguix用户界面配置文件
    :param dry_run: 仅列出不实际删除
    :param force: 不询问直接删除
    """
    # 设置项目路径
    base_dir = os.path.abspath(project_path) if project_path else os.getcwd()
    
    if not os.path.exists(base_dir):
        print(f"错误: 目录不存在 - {base_dir}")
        return
    
    # 检查是否是Keil项目
    if not glob.glob(os.path.join(base_dir, "*.uvproj*")):
        print(f"警告: 目录中未找到Keil项目文件 (*.uvproj*) - {base_dir}")
        if not force:
            confirm = input("是否继续清理? (y/n): ").lower()
            if confirm != 'y':
                print("清理已取消")
                return
    
    dirs, files = list_keil_files(base_dir, keep_uvguix)
    
    if not dirs and not files:
        print("没有找到可清理的文件")
        return
    
    if dry_run:
        print("模拟运行完成 (无文件被删除)")
        return
    
    if not force:
        confirm = input(f"确定要删除以上 {len(dirs)} 个目录和 {len(files)} 个文件吗? (y/n): ").lower()
        if confirm != 'y':
            print("清理已取消")
            return
    
    deleted_count = 0
    
    # 删除目录
    for dir_path in dirs:
        try:
            if os.path.exists(dir_path):
                shutil.rmtree(dir_path)
                print(f"删除目录: {os.path.relpath(dir_path, base_dir)}")
                deleted_count += 1
        except Exception as e:
            print(f"错误: 无法删除 {dir_path} - {str(e)}")
    
    # 删除文件
    for file_path in files:
        try:
            if os.path.exists(file_path):
                os.remove(file_path)
                print(f"删除文件: {os.path.relpath(file_path, base_dir)}")
                deleted_count += 1
        except Exception as e:
            print(f"错误: 无法删除 {file_path} - {str(e)}")
    
    print(f"\n清理完成! 共删除 {deleted_count} 个项目")

if __name__ == "__main__":
    import argparse
    
    parser = argparse.ArgumentParser(
        description='Keil uVision5 项目清理工具',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument('path', nargs='?', default=None, 
                        help='项目路径（默认为当前目录）')
    parser.add_argument('--remove-uvguix', action='store_true',
                        help='同时删除uvguix用户界面配置文件')
    parser.add_argument('--dry-run', action='store_true',
                        help='仅列出要删除的文件，不实际执行删除')
    parser.add_argument('--force', '-f', action='store_true',
                        help='不询问直接删除')
    parser.add_argument('--list', '-l', action='store_true',
                        help='仅列出文件不执行删除')
    
    args = parser.parse_args()
    
    if args.list:
        base_dir = os.path.abspath(args.path) if args.path else os.getcwd()
        list_keil_files(base_dir, keep_uvguix=not args.remove_uvguix)
    else:
        clean_keil_project(
            project_path=args.path,
            keep_uvguix=not args.remove_uvguix,
            dry_run=args.dry_run,
            force=args.force
        )